踩过微信小程序坑的人都知道,微信小程序是不支持cookie的。微信小程序采用的是wx.login获取code,通过开发者服务器端同微信服务器进行数据交互实现登录。得到openid或者unionid与本地数据库关联,从而得到登录用户相关信息。
具体参考微信相关文档wx.login,这里不赘述。
通常情况下,我们不仅仅是需要用户数据,还需要用户的登录状态,也就是session和cookie机制。要命的是小程序不支持cookie,没有了cookie,session也无从谈起。这里基于node.js的express和koa,通过header头添加标记的方式,模拟cookie,从而在服务器端引入session。
cookie的本质是唯一字符串标记,由浏览器自动生成(这里是作为会话方案,而非数据存储方案而言)。既然是唯一字符串标记,那我们也可以自己生成一个类似的标记,添加到Headers头中,类似这样
let header={'x-xxxx-cookie':'uuid cookie'};
//
wx.request({
url:url,
data:data,
header:header,
method:method,
success: function( res ) {
},
fail: function( error ) {
}
});
需要注意的是,这里的uuid cookie最好使用服务器端的session ID,后面再说为什么?
以上就是前端(小程序端)的处理,接下来是服务器端的处理,服务器端使用的是express或者koa,具体使用请移步:
Express
Koa
服务器端Express中session使用的是express-session,Koa中使用的是koa-generic-session,对于Koa这里多说一句,原本也打算使用koa-session,最后放弃选择了前者,因为后者没有暴露出类似获取session ID的参数,而整个过程中需要获取到session ID非常重要。session存储都使用Redis。
Express部分代码如下:
var express = require('express');
var session = require('express-session');
var cookieParser = require('cookie-parser');
var RedisStore = require('connect-redis')(session);
//
var sessionStore=new RedisStore({
host:config.redis.host,
port:config.redis.port
});
var app = express();
//
app.use(cookieParser());
//cookie
var cookieParser=cookieParser(config.secret);
app.use(cookieParser);
//session
var sessionParser = session({
store:sessionStore,
secret:config.secret,
});
app.use(sessionParser);
//
Koa部分代码:
const Koa = require('koa');
const session = require('koa-generic-session');
//const session = require('koa-session');
const RedisStore = require('koa-redis');
//
const app = new Koa();
// middlewares
app.use(bodyparser({
enableTypes:['json', 'form', 'text']
}));
//
let sessionStore=new RedisStore(sessionRedisOptions);
let sessionOptions={
store: sessionStore,
key: '',
};
//
const sessionParser = session(sessionOptions,app);
app.use(sessionParser);
获取session ID,Express中可以直接通过req.sessionID获取得到,koa中使用ctx.sessionId获取得到。之所以session ID重要,主要是我们可以直接通过它获取到session。如果不使用session ID的方式的话,我们需要自己额外去存储相关数据,可以不用将数据挂载到req.session或者ctx.session上,会带来额外的代码成本。而且万一哪天微信小程序支持cookie了呢,采用session ID方式,还是和以前一样操作session数据。
我们需要将session ID从服务器端返回到小程序端,通常会在第一个请求的时候就返回,然后小程序端将该数据保存,类似这样:
app.globalData.cookieID=uuid cookie;//uuid cookie为服务器端返回的session ID
小程序端以后的请求都将该数据添加到Headers头中传递到服务器端。
服务器端下一个请求,直接通过req.session或者ctx.session还是获取不到之前设置的session数据啊!
的确是的,我们需要在路由之前,添加一个中间件来解决。类似这样:
Express部分代码:
app.use(function(req,res,next){
//
var sessionID=req.headers['x-xxxx-cookie'];
if(sessionID){
//
return sessionStore.get(sessionID,function(err,session){
//
req.session=Object.assign(req.session||{},session||{});
//
next();
});
}
//
next();
});
Koa部分代码:
app.use(async function (ctx,next){
//
var cookies=ctx.cookies;
var sessionID=ctx.request.headers['x-xxxx-cookie']||cookies.get(sessionOptions.key);
if(sessionID){
//
let sess= await ctx.sessionStore.get(sessionID);
//
let session=Object.assign(ctx.session||{},sess||{});
ctx.session=session;
}
//
await next();
});
也就是我们需要通过session ID得到session,然后赋值到req.session或者ctx.session上,保证之后可以直接按照普通方式操作session数据。
好了,就到这里,总结一下:
通过header添加类cookie唯一字符串标记,而该字符串标记直接对应服务器端session ID,可以在服务器端直接通过session ID获取到session数据,利用中间件将获取到的session数据赋值给request,从而实现小程序端就像支持cookie一样。
如果引入了socket,比如ws,个中过程又要复杂一些,额外引入其他坑需要填埋,下回再表。
PS:以上为项目部分代码,不保证能够完全运行。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。